package com.wn.realm;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.wn.bean.Permission;
import com.wn.bean.RolePermission;
import com.wn.bean.User;
import com.wn.bean.UserRole;
import com.wn.mapper.UserMapper;
import com.wn.service.IPermissionService;
import com.wn.service.IRolePermissionService;
import com.wn.service.IUserRoleService;
import com.wn.service.IUserService;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.AutoConfigureOrder;
import org.springframework.context.annotation.Lazy;

import java.util.ArrayList;
import java.util.List;

/**
 * @author yellow Docter
 * @date 2022 -05-16
 * @desc
 *   自定义的realm
 *
 *   doGetAuthenticationInfo  认证的方法  返回 一个认证信息
 *
 *
 *   doGetAuthorizationInfo   授权的方法  返回一个授权信息
 *
 */
@Slf4j
public class MyRealm extends AuthorizingRealm {

//    @Autowired
//    private UserMapper UserMapper;

    @Lazy   // 懒惰   使用的时候 在加载
    @Autowired
    IUserService userService;

    // 注入 userRole 中间表操作对象
    @Lazy
    @Autowired
    private IUserRoleService userRoleService;

    // 把 rolePermission 注入进来
    @Lazy
    @Autowired
    private IRolePermissionService rolePermissionService;

    // 注入 permission
    @Lazy
    @Autowired
    private IPermissionService permissionService;

    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {

        /**
         *
         * select * from t_permission where pid in (
         * 		select pid from t_role_permission where rid in (
         * 			select rid from t_user_role where uid = (
         * 				select uid from t_user where username = 'xiao'
         * 		)
         * 	)
         * )
         *
         */
        // 第一步:  拿到user的uid
        User user = (User) principalCollection.getPrimaryPrincipal();
        Integer uid = user.getUid();

        //第二步: 查询 user对应的rid
        //select rid from t_user_role where uid = 1
        QueryWrapper<UserRole> qr = new QueryWrapper<>();
        qr.eq("uid",uid);
        qr.select("rid");
        //listObjs 查询全部记录
        List<Object> rids = userRoleService.listObjs(qr);

        //第三步 查询 role_permission 的 pids
        //select pid from t_role_permission where rid in (1,2);
        QueryWrapper<RolePermission> qrRolePermission = new QueryWrapper<>();
        qrRolePermission.in("rid",rids);
        // 查找指定字段
        qr.select("pid");
        List<Object> pids = rolePermissionService.listObjs(qrRolePermission);

        //第四步: 查询对应的permission
        QueryWrapper<Permission> qrPermission = new QueryWrapper<>();
        qrPermission.in("pid",pids);
        // 通过 pid 从查询对应的 permission
        List<Permission> list = permissionService.list(qrPermission);

        // 第五步 拿到  权限信息
        SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
        for (Permission permission : list) {
            //权限信息
            String pcode = permission.getPcode();
            //添加字符串的权限操作
            authorizationInfo.addStringPermission(pcode);
        }

        //授权信息对象
        return authorizationInfo;
    }

    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {

        String username = (String) authenticationToken.getPrincipal();

        //查询数据库
        QueryWrapper<User> qr = new QueryWrapper<>();
        qr.eq("username",username);
        User user = userService.getOne(qr);
//        User user = UserMapper.selectOne(qr);

        //获取盐 值
        String salt = user.getSalt();
        ByteSource salts = ByteSource.Util.bytes(salt);

        AuthenticationInfo info = new SimpleAuthenticationInfo(
                user,
                user.getPassword(),
                salts,
                getName()
        );
        return info;
    }
}
